package com.siki.provider.service.Impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.siki.provider.dto.contract.BuyCommodityListDTO;
import com.siki.provider.dto.contract.PageContractDTO;
import com.siki.provider.dto.contract.SigningContractDTO;
import com.siki.provider.dto.contract.UpdateContractDTO;
import com.siki.provider.service.ContractService;
import com.siki.provider.vo.contract.ContractCommodityInfoVO;
import com.siki.provider.vo.contract.ContractVO;
import com.siki.salessystemcommon.entity.Commodity;
import com.siki.salessystemcommon.entity.Contract;
import com.siki.salessystemcommon.entity.enumeration.ContractStatusEnum;
import com.siki.salessystemcommon.mapper.CommodityMapper;
import com.siki.salessystemcommon.mapper.ContractMapper;
import com.siki.salessystemcommon.utils.DecimalCalculation;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Siki
 * @date 2020/12/28
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ContractServiceImpl implements ContractService {

    private final ContractMapper contractMapper;
    private final CommodityMapper commodityMapper;

    public ContractServiceImpl(ContractMapper contractMapper, CommodityMapper commodityMapper) {
        this.contractMapper = contractMapper;
        this.commodityMapper = commodityMapper;
    }

    @Override
    public void signingContract(SigningContractDTO dto,
                                String id) {
        Contract contract = new Contract();
        contract.setContractName(dto.getContractName())
                .setContractDescription(dto.getContractDescription())
                .setContractStatus(ContractStatusEnum.SIGN);
        contractMapper.insert(contract);
        UpdateWrapper<Contract> contractUW = new UpdateWrapper<>();
        // 计算合同总金额
        List<BuyCommodityListDTO> dtoList =
                dto.getSigningContractCommodityDTOList();
        String total = getCommodityPrice(dtoList);
        // 合同绑定客户和销售人员
        contractUW.set("client_id", dto.getClientId())
                // 这里是userId
                .set("sales_id", id)
                .set("contract_total_money", total);
        // 绑定合同与商品
        Map<String, Object> map = new HashMap<>();
        map.put("cid", contract.getId());
        map.put("comList", dtoList);
        contractMapper.update(contract, contractUW);
        contractMapper.insertList(map);
    }

    @Override
    public ContractVO getContract(Long id) {
        ContractVO vo = new ContractVO(getContractById(id));
        List<ContractCommodityInfoVO> commodityInfoVOList = new ArrayList<>();
        commodityMapper.getCommodityByContractId(id).forEach(commodity -> {
            commodityInfoVOList.add(new ContractCommodityInfoVO(commodity,
                    commodityMapper.getContractCommodityAmount(id, commodity.getId())));
        });
        vo.setCommodityInfoVOList(commodityInfoVOList);
        return vo;
    }

    @Override
    public synchronized void updateContract(UpdateContractDTO dto,
                               String id) {
        Contract contract = getContractById(dto.getId());
        // 合同状态
        if (!StringUtils.isEmpty(dto.getContractStatus())) {
            contract.setContractStatus(ContractStatusEnum.
                    valueOf(dto.getContractStatus()));
        }
        Assert.isTrue(contract.getContractStatus().equals(ContractStatusEnum.SIGN),
                "只有签订中的合同可以修改");
        Optional.ofNullable(dto.getContractDescription())
                .ifPresent(contract::setContractDescription);
        // 更新商品列表
        Optional.ofNullable(dto.getSigningContractCommodityDTOList())
                .ifPresent(list -> {
                    contractMapper.deleteContractAndCommodity(dto.getId());
                    String total = getCommodityPrice(list);
                    contract.setContractTotalMoney(total);
                    var commodityMap = new HashMap<String, Object>();
                    commodityMap.put("cid", contract.getId());
                    commodityMap.put("comList", list);
                    contractMapper.insertList(commodityMap);
                });
        contractMapper.updateById(contract);
    }

    @Override
    public void deleteContract(Long id) {
        Assert.isTrue(getContractById(id).getContractStatus().equals(ContractStatusEnum.SIGN),
                "只有未履行的合同可以删除");
        contractMapper.deleteById(id);
        contractMapper.deleteContractAndCommodity(id);
    }

    @Override
    public IPage<ContractVO> getPageAllContract(PageContractDTO dto, String id) {
        QueryWrapper<Contract> eq = new QueryWrapper<Contract>()
                .eq("sales_id", id)
                .like("contract_name", dto.getContractName());
        if (!StringUtils.isEmpty(dto.getContractStatus())) {
            eq.eq("contract_status", dto.getContractStatus());
        }
        return new Page<ContractVO>(dto.getPageNo(),
                dto.getPageSize()).setRecords(contractMapper
                .selectPage(new Page<>(dto.getPageNo(),
                                dto.getPageSize()),
                        eq).getRecords()
                .stream()
                .map(Contract::getId)
                .map(this::getContract)
                .collect(Collectors.toList()));
    }

    /**
     * [私有方法] - 根据id查询合同
     *
     * @param id 合同id
     * @return Contract 合同
     */
    private Contract getContractById(Long id) {
        return Optional.ofNullable(contractMapper.selectById(id))
                .orElseThrow(() -> new RuntimeException("该id:" + id + "有误"));
    }

    /**
     * [私有方法] - 根据id查询商品
     *
     * @param id 商品id
     * @return Commodity 商品
     */
    private Commodity getCommodity(Long id) {
        return Optional.ofNullable(commodityMapper.selectById(id))
                .orElseThrow(() -> new RuntimeException("该id:" + id + "有误"));
    }

    /**
     * [私有方法] - 计算合同中商品的总价
     *
     * @param dtoList 商品列表
     * @return 商品的总价
     */
    private String getCommodityPrice(List<BuyCommodityListDTO> dtoList) {
        String total = "0";
        for (BuyCommodityListDTO dto : dtoList) {
            total = DecimalCalculation.add(DecimalCalculation.mul(getCommodity(dto.getId())
                            .getCommodityPrice(),
                    dto.getCommodityAmount()), total);
        }
        return total;
    }
}
